package com.luxsoft.sw3.cfdi;

import java.io.File;
import java.io.FileOutputStream;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import mx.gob.sat.cfd.x3.ComprobanteDocument;
import mx.gob.sat.cfd.x3.ComprobanteDocument.Comprobante;
import mx.gob.sat.cfd.x3.ComprobanteDocument.Comprobante.Complemento;
import mx.gob.sat.cfd.x3.ComprobanteDocument.Comprobante.Conceptos.Concepto;
import mx.gob.sat.cfd.x3.ComprobanteDocument.Comprobante.Emisor;
import mx.gob.sat.cfd.x3.ComprobanteDocument.Comprobante.Receptor;
import mx.gob.sat.cfd.x3.TUbicacion;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperPrintManager;
import net.sf.jasperreports.engine.data.JRTableModelDataSource;
import net.sf.jasperreports.view.JRViewer;
import net.sf.jasperreports.view.JasperViewer;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.xmlbeans.XmlObject;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.stereotype.Service;

import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.GlazedLists;
import ca.odell.glazedlists.gui.TableFormat;
import ca.odell.glazedlists.swing.EventTableModel;

import com.luxsoft.siipap.cxc.model.NotaDeCredito;
import com.luxsoft.siipap.cxc.model.NotaDeCreditoDevolucion;
import com.luxsoft.siipap.model.CantidadMonetaria;
import com.luxsoft.siipap.service.ServiceLocator2;
import com.luxsoft.siipap.util.MonedasUtils;
import com.luxsoft.siipap.ventas.model.Venta;
import com.luxsoft.sw3.cfd.model.ComprobanteFiscal;

@Service("cfdiPrintServices")
public class CFDIPrintServices {
	
	
	
	/**
	 * Permite imprimir el comprobante fiscal tantas veces se requiera
	 * 
	 * @param venta
	 */
	public  JasperPrint impripirComprobante(ComprobanteFiscal cf){
		cf.loadComprobante();
		Comprobante cfdi=cf.getComprobante();
		;
		List<Concepto> list=Arrays.asList(cfdi.getConceptos().getConceptoArray());
		final EventList<Concepto> conceptos=GlazedLists.eventList(list);
		final Map parametros=resolverParametros(cfdi);
		
		
		JasperPrint jasperPrint = null;
		DefaultResourceLoader loader = new DefaultResourceLoader();
		
		String path="file:z:/REPORTES_GASOC/VENTAS/ComprobanteCFDI.jasper";
		Resource res = loader.getResource(path);
		try {
			java.io.InputStream io = res.getInputStream();
			String[] columnas= {"cantidad","NoIdentificacion","descripcion","unidad","ValorUnitario","Importe"}; // 15 17a 17b 16 18 19 
			String[] etiquetas={"cantidad","NoIdentificacion","descripcion","unidad","ValorUnitario","Importe"};
			final TableFormat tf=GlazedLists.tableFormat(columnas, etiquetas);
			
			final EventTableModel tableModel=new EventTableModel(conceptos,tf);
			final JRTableModelDataSource tmDataSource=new JRTableModelDataSource(tableModel);
			jasperPrint = JasperFillManager.fillReport(io, parametros,tmDataSource);
			
			return jasperPrint;
		} catch (Exception ioe) {
			throw new RuntimeException(ExceptionUtils.getRootCauseMessage(ioe),ioe);
		}
		
		
	}
	
	public static void imprimirNotaDeCreditoElectronica(String notaDeCreditoId){
		
		
		NotaDeCredito nota=buscarNotaDeCreditoInicializada(notaDeCreditoId);
		if(nota==null){
			return;
		}
			
		ComprobanteFiscal cf=buscarComprobante(nota.getId());
        JasperPrint jasperPrint=imprimirComprobanteNotaBon(cf);
        JRViewer jasperViewer = new JRViewer(jasperPrint);
        JasperViewer.viewReport(jasperPrint, false);
        
		}
	
private static NotaDeCredito buscarNotaDeCreditoInicializada(final String id){
		
		return (NotaDeCredito)ServiceLocator2.getHibernateTemplate().execute(new HibernateCallback(){

			public Object doInHibernate(Session session) throws HibernateException, SQLException {
				NotaDeCredito res=(NotaDeCredito)session.get(NotaDeCredito.class, id);
				res.getCliente().getTelefonosRow();
				if(!res.getAplicaciones().isEmpty()){
					res.getAplicaciones().iterator().next();
				}
				if(res instanceof NotaDeCreditoDevolucion){
					NotaDeCreditoDevolucion ndev=(NotaDeCreditoDevolucion)res;
					ndev.getDevolucion().getPartidas().iterator().next();
					ndev.getDevolucion().isTotal();
				}
				return res;
			}
			
		});
		
	}
	
public static ComprobanteFiscal buscarComprobante(String origenId){

	String hql="from ComprobanteFiscal c where c.origen=?";
	return (ComprobanteFiscal)ServiceLocator2.getHibernateTemplate().find(hql,origenId).iterator().next();		
}  

	public static JasperPrint imprimirComprobanteNotaBon(ComprobanteFiscal cf){
	
		cf.loadComprobante();
		Comprobante cfdi=cf.getComprobante();
		
		List<Concepto> list=Arrays.asList(cfdi.getConceptos().getConceptoArray());
		final EventList<Concepto> conceptos=GlazedLists.eventList(list);
		final Map parametros=resolverParametros(cfdi);
		
		
		JasperPrint jasperPrint = null;

		DefaultResourceLoader loader = new DefaultResourceLoader();
		
		String path="file:z:/REPORTES_GASOC/VENTAS/ComprobanteCFDI.jasper";
		Resource res = loader.getResource(path);
		try {
			java.io.InputStream io = res.getInputStream();
			String[] columnas= {"cantidad","NoIdentificacion","descripcion","unidad","ValorUnitario","Importe"}; // 15 17a 17b 16 18 19 
			String[] etiquetas={"cantidad","NoIdentificacion","descripcion","unidad","ValorUnitario","Importe"};
			final TableFormat tf=GlazedLists.tableFormat(columnas, etiquetas);
			
			final EventTableModel tableModel=new EventTableModel(conceptos,tf);
			final JRTableModelDataSource tmDataSource=new JRTableModelDataSource(tableModel);
			jasperPrint = JasperFillManager.fillReport(io, parametros,tmDataSource);
			
			return jasperPrint;
		} catch (Exception ioe) {
			throw new RuntimeException(ExceptionUtils.getRootCauseMessage(ioe),ioe);
		}
		
		
	}
	
	public static Map resolverParametros(Comprobante cfdi){
		
		Map<String, Object> parametros = new HashMap<String, Object>();
		
		// Datos tomados del Comprobante fiscal digital XML
		
	
		parametros.put("QR_CODE", QRCodeUtils.generarQR(cfdi));
		
		CantidadMonetaria total=CantidadMonetaria.pesos(cfdi.getTotal());
		parametros.put("IMP_CON_LETRA", 	ImporteALetra.aLetra(total));
		parametros.put("TIPO_CFDI", cfdi.getTipoDeComprobante().toString());
		parametros.put("NUM_CTA_PAGO", cfdi.getNumCtaPago());
		parametros.put("CERTIFICADO_EMISOR", cfdi.getNoCertificado());

		parametros.put("SELLO_DIGITAL_EMISOR", cfdi.getSello());

		Receptor receptor=cfdi.getReceptor();
		parametros.put("RECEPTOR_NOMBRE", 	receptor.getNombre());					
		parametros.put("RECEPTOR_RFC", 		receptor.getRfc());						
		parametros.put("RECEPTOR_DIRECCION", 		CFDUtils.getDireccionEnFormatoEstandar(receptor.getDomicilio()));	

		Emisor emisor=cfdi.getEmisor();
		parametros.put("EMISOR_NOMBRE", 	emisor.getNombre());					// 1
		parametros.put("EMISOR_RFC", 		emisor.getRfc());						// 2
		parametros.put("EMISOR_DIRECCION", CFDUtils.getDireccionEnFormatoEstandar(emisor.getDomicilioFiscal()));						// 3
		
		if (emisor.getExpedidoEn() != null)
		{
			TUbicacion expedido=emisor.getExpedidoEn();	
			System.out.println(CFDUtils.getDireccionEnFormatoEstandar(expedido));
			parametros.put("EXPEDIDO_DIRECCION", CFDUtils.getDireccionEnFormatoEstandar(expedido));							
		}
		else
			parametros.put("EXPEDIDO_DIRECCION", "SNA");
		String regimen=emisor.getRegimenFiscalArray()[0].getRegimen();
		parametros.put("REGIMEN", regimen);
		parametros.put("LUGAR_EXPEDICION", cfdi.getLugarExpedicion());
		parametros.put("FORMA_PAGO", cfdi.getFormaDePago());
		
		parametros.put("FECHA", cfdi.getFecha().getTime());
		parametros.put("FOLIO", cfdi.getFolio());
		parametros.put("SERIE", cfdi.getSerie());
		parametros.put("CONDICIONES_PAGO", cfdi.getCondicionesDePago());
		parametros.put("METODO_PAGO", cfdi.getMetodoDePago());
		parametros.put("IMPORTE_BRUTO", cfdi.getSubTotal());
		parametros.put("DESCUENTOS", cfdi.getDescuento());
		parametros.put("IVA", cfdi.getImpuestos().getTotalImpuestosTrasladados());
		parametros.put("TOTAL", cfdi.getTotal());	

		TimbreFiscal timbre=new TimbreFiscal(cfdi);
		parametros.put("FECHA_TIMBRADO", timbre.FechaTimbrado);
		parametros.put("FOLIO_FISCAL", timbre.UUID);
		parametros.put("SELLO_DIGITAL_SAT", timbre.selloSAT);
		parametros.put("CERTIFICADO_SAT", timbre.noCertificadoSAT);
		parametros.put("CADENA_ORIGINAL_SAT", timbre.cadenaOriginal());
	
		
		return parametros;
	}
	
	public File generarPDF(final ComprobanteFiscal cfdi){
		try {
			JasperPrint jasperPrint=impripirComprobante(cfdi);
			String pdfURL=StringUtils.replace( cfdi.getXmlPath(), ".xml", ".pdf");
			URL url=new URL(pdfURL);
			File pdf=new File(url.toURI());
			FileOutputStream fout=new FileOutputStream(pdf);
			JasperExportManager.exportReportToPdfStream(jasperPrint,fout);
			return pdf;
		} catch (Exception e) {
			throw new RuntimeException(ExceptionUtils.getRootCauseMessage(e),e);
		}
		
	}
	
	
 
}


